package ws.rest.check.base;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.validation.SchemaFactory;

import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.dom4j.DocumentException;
import org.xml.sax.SAXException;

import ws.rest.check.exception.CheckResourceNotValidException;
import ws.rest.check.validator.CheckItem;
import ws.rest.check.validator.CheckResouceParser;
import ws.rest.check.validator.DataChecker;
import ws.rest.check.validator.Validator;

/**
 * TPL 基础类。其他自定自定义tpl实现应该继承改类
 */
public class BaseResourceImpl implements Resource {
	private CheckResouceParser checkParser;
	private Map<String,String> checkXMLsMap = new HashMap<String,String>();
	private Map<String,List<CheckItem>> checkItemsMap = new HashMap<String,List<CheckItem>>();
	private static BaseResourceImpl instance = null;
	private String checkStr;
	
	public BaseResourceImpl() {
		this.checkParser = new CheckResouceParser();
	}
	
	public synchronized static BaseResourceImpl getInstance(){
		if(instance == null)
			instance = new BaseResourceImpl();
		return instance;
	}

	protected String getRawString(String fileName) throws IOException {
		String currDir = DataChecker.class.getClassLoader().getResource("").getPath();
		File file = new File(currDir + "/" + fileName);
		InputStream ins = new FileInputStream(file);
		InputStreamReader insr = new InputStreamReader(ins, "UTF-8");
		BufferedReader br = new BufferedReader(insr);
		StringBuffer sb = new StringBuffer();
		String aLine = null;
		while (null != (aLine = br.readLine())) {
			sb.append(aLine.trim());
			sb.append("\n");
		}
		ins.close();
		insr.close();
		br.close();
		return sb.toString().trim();
	}

	protected String renderFromStr(String str,Map<Object,Object> userData){
		try{
			return VelocityRender.render(str, userData);
		}catch(URISyntaxException e){
			e.printStackTrace();
		} catch (ParseErrorException e) {
			e.printStackTrace();
		} catch (MethodInvocationException e) {
			e.printStackTrace();
		} catch (ResourceNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public List<CheckItem> getCheckResource(Map<Object, Object> userData, String id) {
		String checkFile = "check.xml";
		List<CheckItem> itemList = this.getCheckItemsMap().get(id);
		if(itemList != null)
			return itemList;
		String checkStr = this.getCheckXMLsMap().get(id);
		
		try {
			
			if(checkStr != null && checkStr.length() > 0){
				itemList = this.checkParser.parseCheckResource(checkStr);
				this.getCheckItemsMap().put(id, itemList);
			}else{
				String xml = this.getRawString(checkFile);
				itemList = this.checkParser.parseCheckResource(xml);
				this.getCheckItemsMap().put(id, itemList);
			}
		} catch (DocumentException e) {
			e.printStackTrace();
			System.out.println(checkFile + "解析错误");
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println(checkFile + "读取错误");
		} catch (CheckResourceNotValidException e) {
			e.printStackTrace();
			System.out.println(checkFile + "无效，可能是由于语法错误");
		} catch (SAXException e) {
			e.printStackTrace();
			System.out.println(checkFile + "语法错误");
		}

		return itemList;
	}

	@Override
	public Map<String, Validator> getCustomValidators() {
		return null;
	}

	public String getCheckStr() {
		return this.checkStr;
	}

	public void setCheckStr(String checkStr) {
		this.checkStr = checkStr;
	}

	public Map<String, String> getCheckXMLsMap() {
		return checkXMLsMap;
	}

	public void setCheckXMLsMap(Map<String, String> checkXMLsMap) {
		this.checkXMLsMap = checkXMLsMap;
	}

	public Map<String, List<CheckItem>> getCheckItemsMap() {
		return checkItemsMap;
	}

	public void setCheckItemsMap(Map<String, List<CheckItem>> checkItemsMap) {
		this.checkItemsMap = checkItemsMap;
	}
	
}